﻿// Copyright © Sean Kearon, Atlantic Business Systems.  All rights reserved.
using System.Reflection;
using PostSharp.CodeModel;
using PostSharp.Laos.Weaver;

namespace XpoOneWayMultiAssociationWeaver
{
   /// <summary>
   /// Adds the field that XPO requires as the "other end" of a one-way multi association.
   /// </summary>
   /// <remarks>does a call to the default value advice</remarks>
   public class OtherEndFieldWeaver : TypeLevelAspectWeaver
   {
      #region Constructors

      public OtherEndFieldWeaver(string fieldTypeName, string fieldName, string associationName)
      {
         FieldTypeName = fieldTypeName;
         FieldName = fieldName;
         AssociationName = associationName;
      }

      #endregion

      #region Fields

      private ITypeSignature fieldType;

      #endregion

      #region Methods

      /// <summary>
      /// Implements all the things we need to do on this instance
      /// </summary>
      public override void Implement()
      {
         var module = Task.Project.Module;

         var fieldDeclaration = new FieldDefDeclaration
                                   {
                                      Name = FieldName,
                                      Attributes = FieldAttributes.Public,
                                      FieldType = FieldType
                                   };
         SourceTypeDefDeclaration.Fields.Add(fieldDeclaration);

         var attribute = Utils.CreateAssociationAttribute(module, AssociationName);
         fieldDeclaration.CustomAttributes.Add(attribute);
      }

      #endregion

      #region Properties

      public string AssociationName { get; set; }

      /// <summary>
      /// Gets the type linked by the collection.
      /// </summary>
      /// <value>The type of the linked.</value>
      public ITypeSignature FieldType
      {
         get
         {
            if (fieldType == null)
            {
               fieldType = Task.Project.Module.FindType(FieldTypeName, BindingOptions.Default);
            }
            return fieldType;
         }
      }

      public string FieldTypeName { get; set; }
      private string FieldName { get; set; }

      private TypeDefDeclaration SourceTypeDefDeclaration
      {
         get { return (TypeDefDeclaration) TargetType; }
      }

      #endregion
   }
}